#include "linklog.h"

#include <QDir>
#include <QFile>
#include <QMutexLocker>
#include <QTextStream>
#include <QDateTime>
#include <QCoreApplication>
#include <QDebug>
#include <iostream>
#include <QThread>
#include <signal.h>
#include <QMessageBox>

enum LogFileType{
    LFT_DEBUG = 0,
    LFT_INFO = 1,
    LFT_WARNING = 2,
    LFT_CRITICAL = 3,
    LFT_FATAL = 4,

    LFT_CNT
};

static QFile* LogFiles[LFT_CNT];

void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &m)
{
    QFile* pFile = nullptr;
    QString msg = QString("[%1]").arg((qint64)QThread::currentThreadId());
    switch (type) {
        case QtDebugMsg:
            pFile = LogFiles[LFT_DEBUG];
            msg += "[D]";
            break;
        case QtInfoMsg:
            pFile = LogFiles[LFT_INFO];
            msg += "[I]";
            break;
        case QtWarningMsg:
            pFile = LogFiles[LFT_WARNING];
            msg += "[W]";
            break;
        case QtCriticalMsg:
            pFile = LogFiles[LFT_CRITICAL];
            msg += "[C]";
            break;
        case QtFatalMsg:
            pFile = LogFiles[LFT_FATAL];
            msg += "[F]";
    }

    auto dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    msg += QString("[%0] %1").arg(dt).arg(m);

    QString fname = context.file;
    if(!fname.isEmpty()){
        msg+=QString(" (%0:%1)").arg(QFileInfo(context.file).fileName()).arg(context.line);
    }

    msg += "\r\n";//+  QString(20, '-');

    // 若需要写入文件
    if(pFile != nullptr){
        static QMutex mtx;
        QMutexLocker l(&mtx);
        QTextStream text_stream(pFile);
        text_stream << msg << "\r\n";
        //pFile->flush();
    }

    // 打印
    if (type == QtDebugMsg || type == QtInfoMsg) {
        std::cout << msg.toLocal8Bit().constData() << "";
        std::cout.flush();
    }
    else {
        std::cerr << msg.toLocal8Bit().constData() << "";
    }

    // 若为Fatal，则直接终止进程
   if(type == QtFatalMsg){
       exit(-1);
   }
}

void signalKillHandle(int sig){
    Q_UNUSED(sig);
    qDebug()<<"App Quit";
    exit(0);
}

void initLog(QObject* parent){
    QDir rootDir = QDir(QCoreApplication::applicationDirPath());
    QDir dir(rootDir.filePath("log"));

    // 若不存在对应的文件夹，则新建
    if(!dir.exists()){
        bool succ = rootDir.mkdir("log");
        if(!succ){
            qFatal("Unable to create log directory.");
        }
    }

    QDir back_dir(dir.filePath("backup"));
    if (!back_dir.exists()){
        bool succ = dir.mkdir("backup");
        if(!succ){
            qFatal("Unable to create log back directory.");
        }
    }

    QMap<LogFileType, QString> name_map = {
        {LFT_DEBUG, "log_debug"},
        {LFT_INFO, "log_info"},
        {LFT_WARNING, "log_warning"},
        {LFT_CRITICAL, "log_critical"},
        {LFT_FATAL, "log_fatal"}
    };

    for (auto key : name_map.keys()){
        // 将上一个log文件更名
        auto name = name_map[key];
        QString filename = name + ".txt";

        QFile logFile(dir.filePath(filename));
        if(logFile.exists() && logFile.size() > 0){
            QString logName = back_dir.filePath(QString("%1_%2.txt").arg(name).arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")));
            if(!logFile.rename(logName)){
                qDebug()<<QString("rename log file [%1] to [%2] fail: %3").arg(filename).arg(logName).arg(logFile.errorString());
            }
        }

        // log文件
        QFile *pFile = new QFile(parent);
        Q_ASSERT(pFile != NULL);

        pFile->setFileName(dir.filePath(filename));
        bool succ = pFile->open(QIODevice::WriteOnly | QIODevice::Append);
        if(!succ){
            qDebug()<<QString("Unable to open log file [%1]: %2.").arg(filename).arg(pFile->errorString());
            delete pFile;
            pFile = nullptr;
        }
        else{
            LogFiles[key] = pFile;
        }
    }

    //注册MessageHandler
    qInstallMessageHandler(outputMessage);

    signal(SIGTERM, signalKillHandle);
}

